//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2007
//
// Copy the element of object to another zoom level.
//

# include "StdAfx.h"
# include "SetElementPoints.h"
# include "UndoRedo.h"
# include "Map.h"
# include "Types.h"
# include "Label.h"
# include "Globals.h"

class CSetElementPointsAction : public CEditAction {
  public:
	CSetElementPointsAction (rgn_t * _pRgn, size_t _cElement, const points_t & _points, const point_extras_t & _PointExtras) :
		m_pRgn (_pRgn),
		m_cElement (_cElement),
		m_points (_points),
		m_PointExtras (_PointExtras),
		m_bWasModified ((_pRgn->dwFlags & rgn_t::fModified) != 0)
	{
		assert (m_pRgn);
		assert (m_pRgn->IsPolygon () || m_pRgn->IsPolyline ());
		assert (m_cElement < m_pRgn->elements.size ());
		const rgn_element_t & element = m_pRgn->elements [m_cElement];

		// Round points.
		g_map.pTypeSet->pfRoundPoints (g_map, element.cLevel, m_points);
	}

	virtual void GetName (string_t & _str) const;
	virtual cu_t CanUndo () const {return cuYes;}
	virtual bool Do ();
	virtual void Undo ();
	virtual void Redo ();

  private:
	points_t m_points;
	point_extras_t m_PointExtras;

	rgn_t * const m_pRgn;
	size_t  const m_cElement;
	bool    const m_bWasModified;

	void Swap ();
};

void CSetElementPointsAction::GetName (string_t & _str) const {
	CCritSec::CLock lock (g_cs);

	assert (m_pRgn);
	_str.append ("change points of [");
	GetHintText (* m_pRgn, _str);
	_str.append ("]");
}

bool CSetElementPointsAction::Do () {
	CCritSec::CLock lock (g_cs);

	Swap ();

	assert (m_pRgn);
	m_pRgn->dwFlags |= rgn_t::fModified;
	
	return true;
}

void CSetElementPointsAction::Undo () {
	CCritSec::CLock lock (g_cs);

	Swap ();

	if (! m_bWasModified) {
		assert (m_pRgn);
		m_pRgn->dwFlags &= ~rgn_t::fModified;
	}
}

void CSetElementPointsAction::Redo () {
	CCritSec::CLock lock (g_cs);

	Swap ();

	assert (m_pRgn);
	m_pRgn->dwFlags |= rgn_t::fModified;
}

void CSetElementPointsAction::Swap () {
	assert (m_pRgn);
	assert (m_cElement < m_pRgn->elements.size ());
	rgn_element_t & element = m_pRgn->elements [m_cElement];

	if (element.pExtra || IsNotEmpty (m_PointExtras)) {
		element.ReleaseRGNodes ();

		element.points.swap (m_points);
		element.pExtra->PointExtras.swap (m_PointExtras);

		element.AddRefRGNodes ();
	} else
		element.points.swap (m_points);

	m_pRgn->RefreshAttributes (g_map);
}

////////////////////////////////////////////////

void SetElementPoints (rgn_t * _pRgn, size_t _cElement, const points_t & _points, const point_extras_t & _PointExtras) {
	assert (_pRgn);
	assert (_pRgn->IsPolygon () || _pRgn->IsPolyline ());
	assert (_cElement < _pRgn->elements.size ());

	PerformEditAction (new CSetElementPointsAction (_pRgn, _cElement, _points, _PointExtras));
}
